

#include "GamePlayState.h"
#include "Game.h"
#include "MapManager.h"
#include "Graph.h"
#include "PauseState.h"
#include "LoseGameState.h"

#include "../SGD Wrappers/SGD_AudioManager.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "../SGD Wrappers/SGD_InputManager.h"
#include "../SGD Wrappers/SGD_String.h"

#include "../SGD Wrappers/SGD_EventManager.h"
#include "../SGD Wrappers/SGD_EventManager.h"
#include "../SGD Wrappers/SGD_Event.h"
#include "../SGD Wrappers/SGD_MessageManager.h"
#include "../SGD Wrappers/SGD_Message.h"
#include "MessageID.h"
#include <cassert>
#include "BehaviorManager.h"
#include "Player.h"
#include "Officer.h"
#include "EliteGuard.h"
#include "GuardDog.h"
#include "Turret.h"
#include "Bullet.h"
#include "PickUp.h"
#include "Worker.h"

#include "SecurityCamera.h"
#include "EntityManager.h"
#include "AnimationManager.h"
#include "Animation.h"
#include "Frame.h"
#include "SpawnDoor.h"
#include "CreateBulletMessage.h"
#include "CreateEliteGuardMessage.h"
#include "CreateDogMessage.h"
#include "DestroyObjectMessage.h"
#include "BitmapFont.h"

enum EntityBucket { BUCKET_ENEMIES, BUCKET_PLAYER, BUCKET_ENVIRO, BUCKET_BULLETS, BUCKET_SHADOWS, BUCKET_NONCOLLIDABLE };

/*static*/ GameplayState* GameplayState::GetInstance(void)
{
	static GameplayState s_Instance;	// stored in global memory once
	return &s_Instance;
}

/*virtual*/ void	GameplayState::Enter(void)				/*override*/	// load resources
{
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();


	
	SGD::AudioManager* pAudio = SGD::AudioManager::GetInstance();
	SGD::InputManager* pInput = SGD::InputManager::GetInstance();
	

	SGD::EventManager::GetInstance()->Initialize();
	SGD::MessageManager::GetInstance()->Initialize(&MessageProc);
	BehaviorManager::GetInstance()->Initialize();



	// player animations
	AnimationManager::GetInstance()->Load("resource/config/PlayerAnimation.xml", "player");
	AnimationManager::GetInstance()->Load("resource/config/Player_Idle.xml", "playerIdle");
	AnimationManager::GetInstance()->Load("resource/config/Player_Walking.xml", "playerWalk");
	AnimationManager::GetInstance()->Load("resource/config/Player_Running.xml", "playerRun");
	AnimationManager::GetInstance()->Load("resource/config/Player_Death.xml", "playerDeath");



	// enemy animations
	AnimationManager::GetInstance()->Load("resource/config/EnemyAnimation.xml", "enemy");

	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_Idle.xml", "guardIdle");
	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_Walking.xml", "guardWalk");
	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_Running.xml", "guardRun");
	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_KnockedDown.xml", "guardTakedown");
	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_GettingUp.xml", "guardRecover");
	AnimationManager::GetInstance()->Load("resource/config/BasicGuard_TaserAttack.xml", "guardTaser");

	AnimationManager::GetInstance()->Load("resource/config/CameraAnimation.xml", "camera");
	AnimationManager::GetInstance()->Load("resource/config/WorkerAnimation.xml", "worker");
	AnimationManager::GetInstance()->Load("resource/config/OfficerAnimation.xml", "officer");
	AnimationManager::GetInstance()->Load("resource/config/TurretAnimation.xml", "turret");
	AnimationManager::GetInstance()->Load("resource/config/DogAnimation.xml", "dog");


	// other animations
	AnimationManager::GetInstance()->Load("resource/config/PowerCoreAnimation.xml", "powerCore");
	AnimationManager::GetInstance()->Load("resource/config/keycard.xml", "keycard");
	AnimationManager::GetInstance()->Load("resource/config/Bullet.xml", "bullet");
	AnimationManager::GetInstance()->Load("resource/config/StimPack.xml", "stimPack");

	AnimationManager::GetInstance()->Load("resource/config/Desk.xml", "desk");

	AnimationManager::GetInstance()->Load("resource/config/Computer.xml", "computer");
	AnimationManager::GetInstance()->Load("resource/config/takedown.xml", "takedown");


	

	//background = pGraphics->LoadTexture("resource/graphics/Securityguard.jpg");
	worldImages = pGraphics->LoadTexture("resource/graphics/WorldObjects.png");
	shadows = pGraphics->LoadTexture("resource/graphics/Shadows.png");


	// sounds
	alarmSound = pAudio->LoadAudio("resource/audio/alarmSound.wav");
	cameraRotate = pAudio->LoadAudio("resource/audio/cameraRotate.wav");
	dogBarking = pAudio->LoadAudio("resource/audio/DogChasing.wav");
	dogSniffing = pAudio->LoadAudio("resource/audio/DogSniffing.wav");
	playerDeath = pAudio->LoadAudio("resource/audio/player_death1.wav");
	aware = pAudio->LoadAudio("resource/audio/Alert.wav");
	cannot_use_skill = pAudio->LoadAudio("resource/audio/cannotUseAbility7.wav");
	footstep = pAudio->LoadAudio("resource/audio/FootstepsWood.wav");


	//cameraRotate = pAudio->LoadAudio("resource/audio/alertSound.wav");



	camera.SetSize({ Game::GetInstance()->GetScreenWidth(), Game::GetInstance()->GetScreenHeight() });

	m_pEntities = new EntityManager;
	//m_pPlayer = CreatePlayer();
	//m_pEntities->AddEntity(m_pPlayer, BUCKET_PLAYER);

	//Player* player = dynamic_cast<Player*>(m_pPlayer);
	MapManager::GetInstance()->LoadLevelPaths();
	m_pPlayer = MapManager::GetInstance()->LoadLevel(Game::GetInstance()->GetProfile(), m_pEntities, FOVCollidables, navGraph);

	m_pEntities->AddEntity(m_pPlayer, BUCKET_PLAYER);

	
//	m_tmWorld.LoadLevel("tiles.xml");

	//CreateSecurityCamera();
	////CreateOfficer();
	//CreateLightGuard();
	//CreateTurret();
	//CreateDesk();

	camera.SetTarget(m_pPlayer);


}
/*virtual*/ void	GameplayState::Exit(void)				/*override*/	// unload resources
{
	

	SGD::Event gameOverMsg = { "GAME_OVER", nullptr, this };
	gameOverMsg.SendEventNow();

	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();
	SGD::AudioManager* pAudio = SGD::AudioManager::GetInstance();
	SGD::InputManager* pInput = SGD::InputManager::GetInstance();
	
	pGraphics->UnloadTexture(MapManager::GetInstance()->GetMapTexture());
	pGraphics->UnloadTexture(worldImages);
	pGraphics->UnloadTexture(shadows);


	pAudio->UnloadAudio(alarmSound);
	pAudio->UnloadAudio(cameraRotate);
	pAudio->UnloadAudio(dogBarking);
	pAudio->UnloadAudio(dogSniffing);
	pAudio->UnloadAudio(playerDeath);
	pAudio->UnloadAudio(aware);
	pAudio->UnloadAudio(cannot_use_skill);
	pAudio->UnloadAudio(footstep);

	camera.SetTarget(nullptr);

	for (unsigned int currRect = 0; currRect < FOVCollidables.size(); currRect++)
	{
		delete FOVCollidables[currRect];
		FOVCollidables[currRect] = nullptr;
	}
	FOVCollidables.clear();

	BehaviorManager::GetInstance()->Terminate();
	m_pEntities->RemoveAll();
	delete m_pEntities;
	m_pEntities = nullptr;

	m_pPlayer->Release();
	m_pPlayer = nullptr;




	SGD::EventManager::GetInstance()->Terminate();
	SGD::EventManager::DeleteInstance();

	SGD::MessageManager::GetInstance()->Terminate();
	SGD::MessageManager::DeleteInstance();
	MapManager::GetInstance()->UnloadLevel();
	AnimationManager::GetInstance()->Shutdown();

	for (unsigned int i = 0; i < navGraph.size(); i++)
	{
		delete navGraph.GetVertexElement(i);
	}
	
	navGraph.clear();
	////////////////////////////////////////////////////////////////////////////////////
	// NEED TO DELETE THE CURRENT LEVEL STUFF FROM THE MAP MANAGER
	// OTHERWISE
	// THE NEW LEVEL WILL GET PILED ON TOP OF THE OLD LEVEL
	//
	// E.G.
	//
	// Main Menu -> Gameplay -> Level 1
	//		Lv 1		= 300 tiles
	//		Total tiles	= 300 tiles
	//
	// Gameplay -> Pause -> Restart Level -> Gameplay -> Level 1
	//		Lv 1		= 300 tiles
	//		Total tiles	= 600 tiles
	//
	// Gameplay -> Pause -> Restart Level -> Gameplay -> Level 1
	//		Lv 1		= 300 tiles
	//		Total tiles	= 900 tiles
	//
	// etc........
	////////////////////////////////////////////////////////////////////////////////////


}

/*virtual*/ bool	GameplayState::Input(void)				/*override*/	// handle user input
{
	SGD::InputManager* pInput = SGD::InputManager::GetInstance();

	// Press Escape to quit

	if (pInput->IsKeyPressed(SGD::Key::Escape) == true || pInput->IsButtonDown(0, 9) == true)
	{
		SGD::Event msg("PAUSE");
		msg.SendEventNow();
		Game::GetInstance()->AddState(PauseState::GetInstance());

	}
		//return false;	// quit game


	// Died!
	int numframes = AnimationManager::GetInstance()->GetAnimation("playerDeath")->GetFrames().size();
	numframes--;

	
	if (/*pInput->IsKeyPressed(SGD::Key::Nine) == true || */(m_pPlayer->GetAnimation() == "playerDeath" && m_pPlayer->GetAnimationStamp().m_nCurrFrame == numframes))
	{
		SGD::Event msg("PAUSE");
		msg.SendEventNow();
		Game::GetInstance()->AddState(LoseGameState::GetInstance());
	}

	return true;

}

/*virtual*/ void	GameplayState::Update(float dt)	/*override*/	// update game entities / animations
{
	Player* player = dynamic_cast<Player*>(m_pPlayer);

	if (player->isLevelCompleted() == false)
	{
		m_pEntities->UpdateAll(dt);
		m_pEntities->CheckCollisions(BUCKET_PLAYER, BUCKET_ENEMIES);
		m_pEntities->CheckCollisions(BUCKET_PLAYER, BUCKET_SHADOWS);


		m_pEntities->CheckCollisions(BUCKET_PLAYER, BUCKET_BULLETS);
		m_pEntities->CheckCollisions(BUCKET_BULLETS, BUCKET_ENVIRO);

		m_pEntities->CheckCollisions(BUCKET_PLAYER, BUCKET_ENVIRO);
		m_pEntities->CheckCollisions(BUCKET_ENEMIES, BUCKET_ENVIRO);

		camera.SetPostion({ m_pPlayer->GetPosition().x - Game::GetInstance()->GetScreenWidth() * 0.5f, m_pPlayer->GetPosition().y - Game::GetInstance()->GetScreenHeight() * 0.5f });


		SGD::EventManager::GetInstance()->Update();
		SGD::MessageManager::GetInstance()->Update();


		MapManager::GetInstance()->Update(dt);
	}
	else
	{
		Game::GetInstance()->RemoveState();
		Game::GetInstance()->AddState(GameplayState::GetInstance());
	}
	
	//m_tmWorld.Update(dt);
//	m_tmWorld.Update(dt);

}
/*virtual*/ void	GameplayState::Render(void)				/*override*/	// render game entities / menus
{
	SGD::GraphicsManager* pGraphics = SGD::GraphicsManager::GetInstance();

	//->DrawTexture(background, -GameplayState::GetInstance()->GetCamera()->GetPosition());

	MapManager::GetInstance()->Render();
	//m_tmWorld.Render();
	m_pEntities->RenderAll();

	Player * player = dynamic_cast<Player*>(m_pPlayer);

	float top = 450;
	float left = 435;

	float tops = 475;
	float lefts = 435;

	SGD::Rectangle energyRect = {left, top, left + player->GetAttributes()->m_fCurrEnergy / player->GetAttributes()->m_fMaxEnergy * 150, top + 25};
	//energyRect.Offset({ camera.GetPosition().x, camera.GetPosition().y });

	pGraphics->DrawRectangle(energyRect, { 0, 0, 255 });

	SGD::Rectangle staminaRect = { lefts, tops, lefts + player->GetAttributes()->m_fCurrStamina / player->GetAttributes()->m_fMaxStamina * 150, tops + 25 };
	//staminaRect.Offset({ camera.GetPosition().x, camera.GetPosition().y });

	pGraphics->DrawRectangle(staminaRect, { 0, 255, 0 });

}
BaseObject* GameplayState::CreatePlayer(void)
{
	Player* player = new Player;
	player->SetPosition({ 200, 200 });
	player->SetRotation(0.0f);
	player->SetMoveSpeed(180.0f);
	



	player->RetrieveBehavior("playerController");
	return player;
}

void GameplayState::PauseAudio(bool)
{


}

//void GameplayState::CreateSecurityCamera(void)
//{
//	SecurityCamera* camera = new SecurityCamera;
//	camera->SetPosition({ 500, 500 });
//	camera->SetRotation(0.0f);
//	camera->SetTarget(dynamic_cast<Player*>(m_pPlayer));
//
//	camera->RetrieveBehavior("rotate");
//	camera->SetMoveSpeed(100.0f);
//	camera->GetWaypoints().push_back(SGD::Point(0, 0));
//	camera->GetWaypoints().push_back(SGD::Point(900, 0));
//
//	m_pEntities->AddEntity(camera, BUCKET_ENEMIES);
//	camera->Release();
//	camera = nullptr;
//}
//void GameplayState::CreateOfficer(void)
//{
//	Officer* officer = new Officer;
//	officer->SetPosition({ 500, 500 });
//	officer->SetRotation(0.0f);
//	officer->SetTarget(dynamic_cast<Player*>(m_pPlayer));
//	officer->SetSize({ 64, 64 });
//
//	officer->RetrieveBehavior("runTo");
//	officer->SetMoveSpeed(100.0f);
//	officer->GetWaypoints().push_back(SGD::Point(0, 0));
//	officer->GetWaypoints().push_back(SGD::Point(900, 0));
//
//
//	m_pEntities->AddEntity(officer, BUCKET_ENEMIES);
//	officer->Release();
//	officer = nullptr;
//
//}

void GameplayState::CreateEliteGuard(SpawnDoor* owner)
{
	EliteGuard* eliteGuard = new EliteGuard;
	eliteGuard->SetPosition(owner->GetPosition());
	eliteGuard->SetRotation(0.0f);
	eliteGuard->SetTarget(dynamic_cast<Player*>(m_pPlayer));
	eliteGuard->RetrieveBehavior("runTo");
	eliteGuard->SetMoveSpeed(100.0f);
	eliteGuard->SetHomeNode(owner->GetGraphIndex());
	eliteGuard->SetNavGraph(&navGraph);
	eliteGuard->findFirstPath(owner->GetGraphIndex(), owner->GetWaypoints()[owner->GetNumEnemies() - 1], eliteGuard->GetCurrPath());
	eliteGuard->SetOwner(owner);
	eliteGuard->GetWaypoints().push_back(owner->GetWaypoints()[owner->GetNumEnemies() - 1]);


	m_pEntities->AddEntity(eliteGuard, BUCKET_ENEMIES);
	eliteGuard->Release();
	eliteGuard = nullptr;
}
void GameplayState::CreateDog(SpawnDoor* owner)
{
	GuardDog* dog = new GuardDog;
	dog->SetPosition(owner->GetPosition());
	dog->SetRotation(0.0f);
	dog->SetTarget(dynamic_cast<Player*>(m_pPlayer));
	dog->SetHomeNode(owner->GetGraphIndex());


	dog->SetMoveSpeed(128.0f);
	dog->GetWaypoints().push_back(owner->GetWaypoints()[owner->GetNumEnemies() - 1]);
	dog->SetNavGraph(&navGraph);
	dog->findFirstPath(owner->GetGraphIndex(), dog->GetWaypoints()[0], dog->GetCurrPath());
	dog->SetOwner(owner);

	m_pEntities->AddEntity(dog, BUCKET_ENEMIES);
	dog->Release();
	dog = nullptr;
}


void GameplayState::CreateBullet(EnemyUnit* owner)
{
	Bullet* bullet = new Bullet;
	bullet->SetRotation(owner->GetRotation());
	bullet->SetOwner(owner);
	bullet->SetPosition(owner->GetPosition());
	bullet->SetDirection(owner->GetDirection());
	bullet->SetVelocity(owner->GetDirection() * 800.0f);
	bullet->SetAnimation("bullet");
	


	m_pEntities->AddEntity(bullet, BUCKET_BULLETS);
	bullet->Release();
	bullet = nullptr;

}



/*static*/ void GameplayState::MessageProc(const SGD::Message* pMsg)
{
	/* Show warning when a Message ID enumerator is not handled */
#pragma warning( push )
#pragma warning( 1 : 4061 )

	// What type of message?
	switch (pMsg->GetMessageID())
	{
	case MessageID::MSG_UNKNOWN:
	{


	}
		break;
	case MessageID::MSG_CREATE_BULLET:
	{
		const CreateBulletMessage* pCreateBulletMsg = dynamic_cast<const CreateBulletMessage*>(pMsg);
		GameplayState::GetInstance()->CreateBullet(dynamic_cast<EnemyUnit*>(pCreateBulletMsg->GetOwner()));
		
	}
		break;
	case MessageID::MSG_CREATE_ELITE_GUARD:
	{
		 const CreateEliteGuardMessage* pCreateEliteGuard = dynamic_cast<const CreateEliteGuardMessage*>(pMsg);

		 GameplayState::GetInstance()->CreateEliteGuard(dynamic_cast<SpawnDoor*>(pCreateEliteGuard->GetOwner()));



	}
		break;
	case MessageID::MSG_CREATE_GUARD_DOG:
	{
		const CreateDogMessage* pCreateDogMessage = dynamic_cast<const CreateDogMessage*>(pMsg);

		GameplayState::GetInstance()->CreateDog(dynamic_cast<SpawnDoor*>(pCreateDogMessage->GetOwner()));


	}
		break;

	case MessageID::MSG_DESTROY_OBJECT:
	{
										  const DestroyObjectMessage* pDestroyMsg =
											  dynamic_cast<const DestroyObjectMessage*>(pMsg);

										  assert(pDestroyMsg != nullptr
											  && "Game::MessageProc - MSG_DESTROY_ENTITY is not actually a DestroyEntityMessage");

									/*	  if (pDestroyMsg->GetEntity()->GetType() == Entity::ENT_ENEMY)
											  GameplayState::GetInstance()->m_nNumEnemies--;
										  else if (pDestroyMsg->GetEntity()->GetType() == Entity::ENT_GEN)
											  GameplayState::GetInstance()->m_nNumGenerators--;*/
										  
										  BaseObject* ptr = pDestroyMsg->GetEntity();
										  if (ptr->GetType() == BaseObject::OBJ_DOG)
										  {
											  GuardDog* temp = dynamic_cast<GuardDog*>(ptr);
											  temp->GetOwner()->RemoveEnemy();
										  }
										  if (ptr->GetType() == BaseObject::OBJ_ELITE_GUARD)
										  {
											  EliteGuard* temp = dynamic_cast<EliteGuard*>(ptr);
											  temp->GetOwner()->RemoveEnemy();
										  }
										  // Use the Game singleton to access members!
										  GameplayState::GetInstance()->m_pEntities->RemoveEntity(ptr);

	}
	default:
		break;
	}
#pragma warning( pop )
}


